﻿//-----------------------------------------------------------------------------------------
// <copyright file="BlipiService.cs" company="Jakub Florczyk (www.jakubflorczyk.pl)">
//      Copyright © 2009 Jakub Florczyk (www.jakubflorczyk.pl)
//      http://blipinet.codeplex.com/
// </copyright>
//-----------------------------------------------------------------------------------------

namespace BlipiNET
{
    using System.IO;
    using System.Net;
    using Newtonsoft.Json;

    /// <summary>
    /// Blipi serwis.
    /// </summary>
    public partial class BlipiService
    {
        /// <summary>
        /// Adres api.
        /// </summary>
        private const string ApiUri = "http://api.blipi.pl";

        /// <summary>
        /// Domyślna nazwa aplikacji.
        /// </summary>
#if !PocketPC
        private const string DefaultApplicationName = "BlipiNET";
#else
        private const string DefaultApplicationName = "BlipiNETCF";
#endif

        /// <summary>
        /// Klucz API.
        /// </summary>
        private string key;

        /// <summary>
        /// Nazwa aplikacji.
        /// </summary>
        private string applicationName = DefaultApplicationName;

        /// <summary>
        /// Tworzy nową instancję klasy BlipiService.
        /// </summary>
        public BlipiService()
        {
        }

        /// <summary>
        /// Tworzy nową instancję klasy BlipiService z podanym kluczem.
        /// </summary>
        /// <param name="key">Klucz API.</param>
        public BlipiService(string key)
        {
            this.key = key;
        }

        /// <summary>
        /// Klucz API.
        /// </summary>
        public string Key
        {
            get { return this.key; }
            set { this.key = value; }
        }

        /// <summary>
        /// Nazwa aplikacji.
        /// </summary>
        public string ApplicationName
        {
            get { return this.applicationName; }
            set { this.applicationName = value; }
        }

        /// <summary>
        /// Deserializacja z Json.
        /// </summary>
        /// <typeparam name="T">Typ entity.</typeparam>
        /// <param name="s">String do deserializacji.</param>
        /// <returns>Instancja entity.</returns>
        private static T Deserialize<T>(string s) where T : class
        {
            T t = null;

            using (StringReader sr = new StringReader(s))
            {
                JsonSerializer serializer = new JsonSerializer();
                serializer.MissingMemberHandling = MissingMemberHandling.Ignore;
                t = (T)serializer.Deserialize(sr, typeof(T));
            }

            return t;
        }

        /// <summary>
        /// Deserializacja tablicy z Json.
        /// </summary>
        /// <typeparam name="T">Typ entity.</typeparam>
        /// <param name="s">String do deserializacji.</param>
        /// <returns>Tablica instancji entity.</returns>
        private static T[] DeserializeMany<T>(string s) where T : class
        {
            T[] t = null;

            using (StringReader sr = new StringReader(s))
            {
                JsonSerializer serializer = new JsonSerializer();
                serializer.MissingMemberHandling = MissingMemberHandling.Ignore;
                t = (T[])serializer.Deserialize(sr, typeof(T[]));
            }

            return t;
        }

        /// <summary>
        /// Odczyt odpowiedzi.
        /// </summary>
        /// <param name="response">HttpWebResponse odpowiedzi.</param>
        /// <returns>String odpowiedzi.</returns>
        private static string ReadResponse(HttpWebResponse response)
        {
            string s = string.Empty;

            using (StreamReader sr = new StreamReader(response.GetResponseStream()))
            {
                s = sr.ReadToEnd();
                sr.Close();
            }
            
            return s;
        }        

        /// <summary>
        /// Żądanie typu "GET".
        /// </summary>
        /// <typeparam name="T">Typ entity.</typeparam>
        /// <param name="query">Zapytanie serwera.</param>
        /// <returns>Instancję entity.</returns>
        private T RequestGet<T>(string query) where T : class
        {
            HttpWebRequest request;
            HttpWebResponse response;

            request = this.CreateRequest(query, "GET");
            response = (HttpWebResponse)request.GetResponse();

            string responseString = ReadResponse(response);

            response.Close();
            request.Abort();
            response = null;
            request = null;

            T t = Deserialize<T>(responseString);

            return t;
        }

        /// <summary>
        /// Żądanie typu "GET" zwracające tablicę.
        /// </summary>
        /// <typeparam name="T">Typ entity.</typeparam>
        /// <param name="query">Zapytanie serwera.</param>
        /// <returns>Tablica instancji entity.</returns>
        private T[] RequestGetMany<T>(string query) where T : class
        {
            HttpWebRequest request;
            HttpWebResponse response;

            request = this.CreateRequest(query, "GET");
            response = (HttpWebResponse)request.GetResponse();

            string responseString = ReadResponse(response);

            response.Close();
            request.Abort();
            response = null;
            request = null;

            T[] t = DeserializeMany<T>(responseString);

            return t;
        }

        /// <summary>
        /// Utworzenie żądania.
        /// </summary>
        /// <param name="query">Zapytanie serwera.</param>
        /// <param name="method">Metoda żądania.</param>
        /// <returns>Żądanie HttpWebRequest.</returns>
        private HttpWebRequest CreateRequest(string query, string method)
        {
            HttpWebRequest request;
            request = (HttpWebRequest)HttpWebRequest.Create(ApiUri + query);
            request.Method = method;
            request.UserAgent = this.applicationName;

            request.KeepAlive = false;
            request.AllowWriteStreamBuffering = true;
            return request;
        }
    }
}
